using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;
using Caliburn.Micro;
using Action = System.Action;

namespace MediaOwl.Core.Modularity
{
    public class LoadCatalog : IResult
    {
        private readonly Uri uri;
        private readonly IModuleManager moduleManager;
        private readonly Action onSuccess;
        private readonly Action<Exception> onFail;

        [Import]
        public AggregateCatalog Catalog { get; set; }

        public LoadCatalog(Uri uri, IModuleManager moduleManager, Action onSuccess, Action<Exception> onFail)
        {
            this.uri = uri;
            this.moduleManager = moduleManager;
            this.onSuccess = onSuccess;
            this.onFail = onFail;
        }

        public void Execute(ActionExecutionContext context)
        {
            var catalog = moduleManager.GetCatalog(uri.ToString());

            if (catalog != null)
            {
                if (onSuccess != null)
                    Caliburn.Micro.Execute.OnUIThread(() => onSuccess());
                Completed(this, new ResultCompletionEventArgs());
            }
            else
            {
                catalog = new DeploymentCatalog(uri);
                catalog.DownloadCompleted += (s, e) =>
                {
                    if (e.Error == null)
                    {
                        ((ModuleManager)moduleManager).AddCatalog(catalog);
                        Catalog.Catalogs.Add(catalog);
                        catalog.Parts
                            .Select(part => ReflectionModelServices.GetPartType(part).Value.Assembly)
                            .Where(assembly => !AssemblySource.Instance.Contains(assembly))
                            .Apply(x => AssemblySource.Instance.Add(x));

                        var module = moduleManager.Modules.FirstOrDefault(x => x.Uri == uri);
                        if (module != null)
                            module.Loaded = true;

                        if (onSuccess != null)
                            Caliburn.Micro.Execute.OnUIThread(() => onSuccess());
                    }
                    else
                    {
                        if (onFail != null)
                            Caliburn.Micro.Execute.OnUIThread(() => onFail(e.Error));
                    }

                    Completed(this, new ResultCompletionEventArgs
                    {
                        Error = e.Error,
                        WasCancelled = false
                    });
                };

                catalog.DownloadAsync();
            }
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    }
}